import random
import wx

import pyciv.action
import pyciv.dictionary
import pyciv.hexagon
import pyciv.player
import pyciv.resources
import pyciv.rules
import pyciv.state
import pyciv.terrain
import pyciv.worker

"""
Engine phases
2| Before player
 | player (None/Human/AI)
 | After player
3 End turn
"""

class GameOver(Exception):
    def __init__(self, message):
        self.message = message

class Engine(object):

    def __init__(self):
        self.state = pyciv.state.State(5)
        self.actions = []
        self.hex_action = pyciv.dictionary.WithDefault(self.state.valid_hex, pyciv.action.NONE)
        self.current_hex = None

    def create_default_state(self):
        random.seed(13786)
        for hex in self.state.hexes:
            self.state.terrain[hex] = random.choice(pyciv.terrain.DISTRIBUTION)

        self._add_player(pyciv.player.Human(wx.BLUE, "First"), (0, 0, 0))
        self._add_player(pyciv.player.Computer(wx.RED, "Second"), (4, 0, 4))
        self._add_player(pyciv.player.Computer(wx.GREEN, "Third"), (-4, 0, -4))

    def _add_player(self, player, hex):
        self.state.players.append(player)
        self.state.owner[hex] = player
        self.state.worker[hex] = pyciv.worker.Farmer()
        self.state.owner[pyciv.hexagon.add(hex, pyciv.hexagon.RIGHT)] = player

    def end_turn(self):
        """End current player turn"""
        self._next_player()
        self.play_game()

    def play_game(self):
        while self.state.players[self.state.current_player].do_turn(self):
            self._next_player()

    def current_player(self):
        return self.state.players[self.state.current_player]

    def _next_player(self):
        # Check game over
        if not self.current_player().is_default_player():
            self._game_over()

        # Clear all selections
        self.deselect()
        
        # Perform operations AFTER player
        self.current_player().after_turn(self)

        self.state.current_player += 1
        if self.state.current_player == len(self.state.players):
            self.state.current_player = 0
            self.state.turn += 1

        # Perform operations BEFORE player
        self.current_player().before_turn(self)
    
    def _game_over(self):
        (hexes, other_hexes, workers, other_workers) = self.current_player().count_status(self)
        
        if hexes > other_hexes:
            raise GameOver("Player %s won!\nMore then half of the hexes." % self.current_player().name)
        
        if workers > other_workers:
            raise GameOver("Player %s won!\nMore then half of the workers." % self.current_player().name)
        
        if self.state.turn == pyciv.rules.TURN_LIMIT:
            raise GameOver("Reached turn %d" % pyciv.rules.TURN_LIMIT)

    def current_player_owns(self, hex):
        return self.state.owner[hex] == self.current_player()

    def next_to_current_hex(self, hex):
        for neighbour in pyciv.hexagon.get_neighbours(self.current_hex):
            if hex == neighbour:
                return True
        return False

    def execute_action(self, index):
        self.actions[index].execute(self)
        self.deselect()

    def generate_actions(self):
        if self.current_hex is not None:
            for hex in self.state.hexes:
                self.hex_action[hex] = self.state.worker[self.current_hex].generate_hex_action(hex, self)
            self.actions = self.state.worker[self.current_hex].generate_actions(self.current_hex, self)

    def select(self, hex):
        if self.current_hex is None:
            if self.state.owner[hex] == self.current_player():
                self.current_hex = hex
                self.generate_actions()
        else:
            self.hex_action[hex].execute(self)
            self.deselect()

    def deselect(self):
        self.current_hex = None
        self.hex_action.clear()
        self.actions = []
        
    def can_end_turn(self):
        result = [True, "End current turn"]
        income = self.current_player().calculate_income(self)
        for resource in [pyciv.resources.FOOD, pyciv.resources.GOLD]:
            if (income[resource] + self.current_player().resources[resource]) < 0:
                result[0] = False
                result[1] = "Running out of %s" % resource
                
        return result

    def sum_for_player(self, hex, player, resource):
        result = 0
        if player == self.state.players[0]:
            return 1
        
        neighbours = pyciv.hexagon.get_neighbours(hex)
        neighbours.append(hex)
        for neighbour in neighbours:
            if self.state.owner[neighbour] == player:
                try:
                    result += self.state.worker[neighbour].income(self.state.terrain[neighbour])[resource]
                except KeyError:
                    pass
        return result
